/*
 *  IdleTime.c
 *  Pennyworth
 *
 *  Created by Chris Karr on 12/24/07.
 *  Copyright 2007 Chris J. Karr. All rights reserved.
 *
 */

#include "IdleTime.h"

#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h>
#include <IOKit/IOKitLib.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

/* 10^9 --  number of ns in a second */
#define NS_SECONDS 1000000000

long getSystemIdleTime () 
{
	long idle = 0;
	
	mach_port_t masterPort;
	io_iterator_t iter;
	io_registry_entry_t curObj;

	IOMasterPort (MACH_PORT_NULL, &masterPort);

	/* Get IOHIDSystem */
	IOServiceGetMatchingServices (masterPort, IOServiceMatching ("IOHIDSystem"), &iter);
	if (iter == 0) 
	{
		printf ("Error accessing IOHIDSystem\n");
		return idle;
	}

	curObj = IOIteratorNext(iter);

	if (curObj == 0) 
	{
		printf ("Iterator's empty!\n");
		return idle;
	}

	CFMutableDictionaryRef properties = 0;
	CFTypeRef obj;

	if (IORegistryEntryCreateCFProperties(curObj, &properties, kCFAllocatorDefault, 0) == KERN_SUCCESS && properties != NULL) 
	{
		obj = CFDictionaryGetValue (properties, CFSTR ("HIDIdleTime"));
		CFRetain (obj);
	} 
	else 
	{
		printf ("Couldn't grab properties of system\n");
		obj = NULL;
	}

	if (obj) 
	{
		uint64_t tHandle;

		CFTypeID type = CFGetTypeID (obj);

		if (type == CFDataGetTypeID()) 
			CFDataGetBytes ((CFDataRef) obj, CFRangeMake (0, sizeof (tHandle)), (UInt8*) &tHandle);
		else if (type == CFNumberGetTypeID()) 
			CFNumberGetValue ((CFNumberRef) obj, kCFNumberSInt64Type, &tHandle);
		else
		{
			CFRelease(obj);

			printf("%d: unsupported type\n", (int)type);
			return idle;
		}

		CFRelease(obj);

		// essentially divides by 10^9
		tHandle >>= 30;

		idle = tHandle;
	}
	else 
		printf("Can't find idle time\n");

	/* Release our resources */
	IOObjectRelease(curObj);
	IOObjectRelease(iter);
	CFRelease((CFTypeRef)properties);

	return idle;
}